package wang.conge.javasedemo.core.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author conge
 * 2016年7月14日
 */
public class NonBlockingIOServer {
	
	private  int BLOCK = 4096;
	private  ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
	private  ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
	private  Selector selector;
	
	
	public NonBlockingIOServer(int port) throws IOException {
		//1.open  ServerSocketChannel
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		//2.configureBlocking false
		serverSocketChannel.configureBlocking(false);
		//3.bind port
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		
		//4.open  Selector
		selector = Selector.open();
		//5.serverSocketChannel register select
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		
		System.out.println("Server Start,port:"+port);
	}

	private void accept() throws IOException {
		while (true) {
			// 1.select,block
			selector.select();
			
			// 2.SelectionKey iterator
			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
			while (iterator.hasNext()) {
				SelectionKey selectionKey = iterator.next();
				iterator.remove();
				try {
					doAccept(selectionKey);
				} catch (IOException e) {
					selectionKey.cancel();
					e.printStackTrace();
				}
			}
		}
	}

	private void doAccept(SelectionKey selectionKey)throws IOException{
		if (selectionKey.isAcceptable()) {
			// ServerSocketChannel 的 selectionKey
			ServerSocketChannel server = (ServerSocketChannel) selectionKey.channel();
			if(null == server){
				return;
			}
			
			//接受到此通道套接字的连接,block here
			SocketChannel client = server.accept(); 
			// 配置为非阻塞
			client.configureBlocking(false);   
			
			// 注册读到selector，等待读的selectionKey
			client.register(selector, SelectionKey.OP_READ);
		} else if (selectionKey.isReadable()) {
			// SocketChannel 的 selectionKey
			SocketChannel client = (SocketChannel) selectionKey.channel();
			
			receiveBuffer.clear();
			int count = client.read(receiveBuffer);	
			if (count > 0) {
				String receiveText = new String( receiveBuffer.array(),0,count);
				System.out.println(receiveText);
				//注册写到selector，等待读的selectionKey
				SelectionKey key = client.register(selector, SelectionKey.OP_WRITE);
				//这里可以作为设计框架的扩展之处
				key.attach(receiveText);
			}
		} else if (selectionKey.isWritable()) {
			// SocketChannel selectionKey
			SocketChannel client = (SocketChannel) selectionKey.channel();
			
			//取出read 的 attachment
			String request = (String) selectionKey.attachment();
			String sendText="response--" + request;
			
			sendBuffer.clear();
			sendBuffer.put(sendText.getBytes());
			sendBuffer.flip();
			
			//输出到通道
			client.write(sendBuffer);
			System.out.println(sendText);
			client.register(selector, SelectionKey.OP_READ);
		}
	}

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		int port = 10000;
		NonBlockingIOServer server = new NonBlockingIOServer(port);
		server.accept();
	}
}